package com.java.example.ui.update

import android.os.Handler
import android.os.Looper
import android.os.Message
import java.io.IOException
import java.io.InputStream
import java.io.InterruptedIOException
import java.io.RandomAccessFile
import java.net.HttpURLConnection
import java.net.URL
import java.text.DecimalFormat

class UpdateDownloadRequest(private val downloadUrl: String, private val localFilePath: String, private val listener: UpdateDownloadListener) : Runnable {
    private var isDownloading = false
    private var currentLength: Long = 0

    private val downloadResponseHandler: DownloadResponseHandler

    init {
        this.isDownloading = true
        downloadResponseHandler = DownloadResponseHandler()
    }

    private fun getTwoPointFloatStr(value: Float): String {
        val df = DecimalFormat("0.00000000000")
        return df.format(value.toDouble())
    }

    @Throws(IOException::class, InterruptedIOException::class)
    private fun makeRequest() {
        if (!Thread.currentThread().isInterrupted) {
            try {
                val url = URL(downloadUrl)
                val connection = url.openConnection() as HttpURLConnection
                connection.requestMethod = "GET"
                connection.connectTimeout = 5000
                connection.setRequestProperty("Connection", "Keep-Alive")
                connection.connect()
                currentLength = connection.contentLength.toLong()
                if (!Thread.currentThread().isInterrupted) {
                    downloadResponseHandler.sendResponseMessage(connection.inputStream)
                }
            } catch (e: Exception) {
                throw e
            }
        }
    }


    override fun run() {
        try {
            makeRequest()
        } catch (e: IOException) {
        }
    }

    /**
     * 下载过程中的异常
     */
    enum class FailureCode {
        UnknownHost, Socket, SocketTimeout, connectionTimeout, IO, HttpResponse,
        Json, Interrupted
    }

    inner class DownloadResponseHandler {
        private var completeSize = 0f
        private var progress = 0

        private val handler: Handler?

        init {
            handler = object : Handler(Looper.getMainLooper()) {
                override fun handleMessage(msg: Message) {
                    handleSelfMessage(msg)
                }
            }
        }


        protected fun sendFinishMessage() {
            sendMessage(obtainMessage(Companion.FINISH_MESSAGE, null))
        }

        private fun sendProgressChangedMessage(progress: Int) {
            sendMessage(obtainMessage(Companion.PROGRESS_CHANGED, arrayOf<Any>(progress)))
        }

        protected fun sendFailureMessage(failureCode: FailureCode) {
            sendMessage(obtainMessage(Companion.FAILURE_MESSAGE, arrayOf<Any>(failureCode)))
        }

        protected fun sendMessage(msg: Message?) {
            handler?.sendMessage(msg!!) ?: handleSelfMessage(msg)
        }

        protected fun obtainMessage(responseMessge: Int, response: Any?): Message? {
            var msg: Message? = null
            if (handler != null) {
                msg = handler.obtainMessage(responseMessge, response)
            } else {
                msg = Message.obtain()
                msg.what = responseMessge
                msg.obj = response
            }
            return msg
        }

        protected fun handleSelfMessage(msg: Message?) {
            val response: Array<Any>
            when (msg!!.what) {
                Companion.FAILURE_MESSAGE -> {
                    response = msg.obj as Array<Any>
                    sendFailureMessage(response[0] as FailureCode)
                }

                Companion.PROGRESS_CHANGED -> {
                    response = msg.obj as Array<Any>
                    handleProgressChangedMessage((response[0] as Int))
                }

                Companion.FINISH_MESSAGE -> onFinish()
            }
        }

        protected fun handleProgressChangedMessage(progress: Int) {
            listener.onProgressChanged(progress, downloadUrl)
        }

        protected fun onFinish() {
            listener.onFinished(completeSize, "")
        }

        private fun handleFailureMessage(failureCode: FailureCode) {
            onFailure(failureCode)
        }

        protected fun onFailure(failureCode: FailureCode?) {
            listener.onFailure()
        }

        fun sendResponseMessage(`is`: InputStream?) {
            var randomAccessFile: RandomAccessFile? = null
            completeSize = 0f
            try {
                val buffer = ByteArray(5120)
                var length = -1 //读写长度
                var limit = 0
                randomAccessFile = RandomAccessFile(localFilePath, "rwd")
                while ((`is`!!.read(buffer).also { length = it }) != -1) {
                    if (isDownloading) {
                        randomAccessFile.write(buffer, 0, length)
                        completeSize += length.toFloat()
                        if (completeSize < currentLength) {
//                            Log.e("tag", "completeSize="+completeSize);
//                            Log.e("tag", "currentLength="+currentLength);
                            progress = (getTwoPointFloatStr(completeSize / currentLength).toFloat() * 100).toInt()
                            //                            Log.e("tag", "下载进度："+progress);
                            if (limit % 30 == 0 && progress <= 100) { //隔30次更新一次notification
                                sendProgressChangedMessage(progress)
                            }
                            limit++
                        }
                    }
                }
                sendFinishMessage()
            } catch (e: IOException) {
                sendFailureMessage(FailureCode.IO)
            } finally {
                try {
                    `is`?.close()
                    randomAccessFile?.close()
                } catch (e: IOException) {
                    sendFailureMessage(FailureCode.IO)
                }
            }
        }
    }

    companion object {
        protected const val SUCCESS_MESSAGE: Int = 0
        protected const val FAILURE_MESSAGE: Int = 1
        protected const val START_MESSAGE: Int = 2
        protected const val FINISH_MESSAGE: Int = 3
        protected const val NETWORK_OFF: Int = 4
        private const val PROGRESS_CHANGED = 5
    }
}
